/**
 * @file tabs.c
 * @author yonglin_zhang
 * @brief 制表符模块实现
 * @version 0.1
 * @date 2024-06-03
 * 
 * @copyright Copyright (c) 2024
 * 
 */

#include "tabs.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>

typedef struct node{
    char *value;
    struct node *next;
}node;

typedef struct tab_data {
    node head;
    struct tab_data * next;
}tab_data;

struct tab_handler{
    node      handler_header;   // 表头
    tab_data  handler_data;     // 表数据
    tab_data *rear;             // 表数据队尾
    int       column_num;       // 列数
    int      *column_max;       // 每列最大个数
};

/**
 * @brief 释放单链表，包含head
 * 
 * @param head 链表头
 * @return int 
 */
static void internal_link_list_free(node *head) {
    node *free_ptr = NULL;
    while(head != NULL) {
        free_ptr = head;
        head = head->next;
        free(free_ptr->value);
        free(free_ptr);
    }
}

/**
 * @brief 通过变参参数添加数据
 * 
 * @param max[in] 每列最大计数器，其大小严格与param_count相等
 * @param head[in] 表头
 * @param args[in] 变参
 */
static int internal_add_node_by_args(int max[], node *head, int param_count, va_list args) {
    int counter = 0;
    int length = 0;
    const char *current_arg_ptr = NULL;

    va_list temp_args;
    va_copy(temp_args, args);

    // 拿到第一个数据
    current_arg_ptr = va_arg(temp_args, const char *);
    counter = 1;

    while(counter <= param_count) {
        if(current_arg_ptr == NULL) {
            va_end(temp_args);
            return COMMON_TABS_BAD_INPUT;
        }
        current_arg_ptr = va_arg(temp_args, const char *);
        counter++;
    }
    va_end(temp_args);

    // 拿到第一个数据
    current_arg_ptr = va_arg(args, const char *);
    counter =1;

    while(counter <= param_count) {
        if(current_arg_ptr == NULL) {
            return COMMON_TABS_BAD_INPUT;
        }
        // 添加节点，尾插法
        length = strlen(current_arg_ptr) + 1;
        node *node_ptr = (node *)malloc(sizeof(node));
        node_ptr->value = (char *)malloc(sizeof(char) * length);
        strcpy(node_ptr->value, current_arg_ptr);
        node_ptr->next = NULL;
        head->next = node_ptr;
        head = node_ptr;

        // 更新每列最大长度
        // if(max[counter - 1] < length) {
        //     max[counter - 1] = length;
        // }
        max[counter - 1] = max[counter - 1] > length ? max[counter - 1] : length;

        // 指针后移
        current_arg_ptr = va_arg(args, const char *);
        counter++;
    }
    return COMMON_TABS_OK;
}

typedef enum {
    LINE_TYPE1,
    LINE_TYPE2,
    LINE_TYPE3
}LINE_TYPE;

/**
 * @brief 打印特殊行
 * 
 * @param handler 
 */
static void internal_print_special_line_unicode(tab_handler *handler, LINE_TYPE line_type) {
    int i = 0, j = 0;
    switch (line_type)
    {
    case LINE_TYPE1:
        printf("┌");
        break;
    case LINE_TYPE2:
        printf("├");
        break;
    case LINE_TYPE3:
        printf("└");
        break;
    }
    for(i = 0; i < handler->column_num; i++) {
        for(j = 0; j < handler->column_max[i] + 2; j++) {
            printf("─");
        }
        if(i != handler->column_num - 1) {
            switch (line_type)
            {
            case LINE_TYPE1:
                printf("┬");
                break;
            case LINE_TYPE2:
                printf("┼");
                break;
            case LINE_TYPE3:
                printf("┴");
                break;
            }
        }
        else {
            switch (line_type)
            {
            case LINE_TYPE1:
                printf("┐");
                break;
            case LINE_TYPE2:
                printf("┤");
                break;
            case LINE_TYPE3:
                printf("┘");
                break;
            }
        }
    }
    printf("\n");
}

static void internal_print_special_line_ascii(tab_handler *handler) {
    int i = 0, j = 0;
    printf("+");
    for(i = 0; i < handler->column_num; i++) {
        for(j = 0; j < handler->column_max[i] + 2; j++) {
            printf("-");
        }
        printf("+");
    }
    printf("\n");
}

typedef enum {
    PRINTF_FORMAT_UNICODE,
    PRINTF_FORMAT_ASCII,
}PRINTF_FORMAT;

/**
 * @brief 打印表头
 * 
 * @param handler 
 */
static void internal_print_table_header(tab_handler *handler, PRINTF_FORMAT format) {
    int counter = 0;
    node *head = handler->handler_header.next;
    if(format == PRINTF_FORMAT_UNICODE) {
        printf("│");
    }
    else {
        printf("|");
    }
    while(head != NULL) {
        if(format == PRINTF_FORMAT_UNICODE) {
            printf(" %-*s │", handler->column_max[counter], head->value);
        }
        else {
            printf(" %-*s |", handler->column_max[counter], head->value);
        }
        head = head->next;
        counter++;
    }
    printf("\n");
}

/**
 * @brief 打印表内数据
 * 
 * @param handler 
 */
static void internal_print_table_data(tab_handler *handler, PRINTF_FORMAT format) {
    int counter = 0;
    tab_data *data_head = NULL;
    node *line_head = NULL;

    data_head = handler->handler_data.next;
    while(data_head != NULL) {
        if(format == PRINTF_FORMAT_UNICODE) {
            printf("│");
        }
        else {
            printf("|");
        }
        line_head = data_head->head.next;
        counter = 0;
        while(line_head != NULL) {
            if(format == PRINTF_FORMAT_UNICODE) {
                printf(" %-*s │", handler->column_max[counter], line_head->value);
            }
            else {
                printf(" %-*s |", handler->column_max[counter], line_head->value);
            }

            line_head = line_head->next;
            counter++;
        }
        data_head = data_head->next;
        printf("\n");
    }

}

int common_tabs_init(tab_handler ** handler) {
    if(handler == NULL) {
        return COMMON_TABS_BAD_INPUT;
    }
    if(*handler != NULL) {
        return COMMON_TABS_ALREADY_INITED;
    }

    *handler = (tab_handler *)malloc(sizeof(tab_handler));
    if(*handler == NULL) {
        return COMMON_TABS_MALLOC_FAILED;
    }

    (*handler)->handler_header.next = NULL;
    (*handler)->handler_header.value = NULL;

    (*handler)->handler_data.head.next = NULL;
    (*handler)->handler_data.head.value = NULL;
    (*handler)->handler_data.next = NULL;

    (*handler)->rear = &(*handler)->handler_data;

    (*handler)->column_num = 0;

    return COMMON_TABS_OK;
}

int common_tabs_free(tab_handler ** handler) {
    /*=================
    1. 循环释放表头
    2. 循环释放handler_data
    3. 如果column_num != 0，释放column_max
    4. 释放根节点
    5. 根节点置为NULL
    ==================*/

    if(handler == NULL) {
        return COMMON_TABS_BAD_INPUT;
    }

    if(*handler == NULL) {
        return COMMON_TABS_OK;
    }

    tab_data *free_ptr_data = NULL;
    tab_data *free_ptr_temp = NULL;

    // step1
    internal_link_list_free((*handler)->handler_header.next);

    // step2
    free_ptr_data = (*handler)->handler_data.next;
    while(free_ptr_data != NULL) {
        free_ptr_temp = free_ptr_data;
        free_ptr_data = free_ptr_data->next;
        internal_link_list_free(free_ptr_temp->head.next);
        free(free_ptr_temp);
    }

    // step3
    if((*handler)->column_num != 0) {
        free((*handler)->column_max);
    }

    // step4
    free(*handler);

    // step5
    *handler = NULL;

    return COMMON_TABS_OK;
}

int common_tabs_add_header(tab_handler *handler, int header_count, ...) {
    va_list args;
    int ret = 0;

    if(handler == NULL || header_count <= 0) {
        return COMMON_TABS_BAD_INPUT;
    }

    if(handler->handler_header.next != NULL) {
        return COMMON_TABS_ALREADY_INITED;
    }

    // 为每行最大计数器进行申请内存
    handler->column_max = NULL;
    handler->column_max = (int*)malloc(sizeof(int) * header_count);
    if(handler->column_max == NULL) {
        return COMMON_TABS_MALLOC_FAILED;
    }

    // 初始化数值
    memset(handler->column_max, 0, sizeof(int) * header_count);

    handler->column_num = header_count;

    // 添加节点的同时并获得每列的最大值，同时更新到column中
    va_start(args, header_count);
    ret = internal_add_node_by_args(handler->column_max, &handler->handler_header, header_count, args);
    va_end(args);

    if(ret != COMMON_TABS_OK) {
        free(handler->column_max);
        handler->column_max = NULL;
    }

    return ret;
}

int common_tabs_add_data(tab_handler *handler, int data_count, ...) {
    va_list args;
    int ret = 0;
    tab_data *incoming_node = NULL;

    // 非法参数
    if(handler == NULL || data_count <= 0) {
        return COMMON_TABS_BAD_INPUT;
    }

    // 未添加表头
    if(handler->handler_header.next == NULL) {
        return COMMON_TABS_HEADERS_ARE_REQUIRED;
    }

    // 长度检查
    if(data_count != handler->column_num) {
        return COMMON_TABS_HEADER_AND_DATA_MISMATCH;
    }

    // 申请内存
    incoming_node = (tab_data *)malloc(sizeof(tab_data));
    if(incoming_node == NULL) {
        return COMMON_TABS_MALLOC_FAILED;
    }

    // 初始化数据
    incoming_node->head.next = NULL;
    incoming_node->head.value = NULL;
    incoming_node->next = NULL;

    // 添加数据
    va_start(args, data_count);
    ret = internal_add_node_by_args(handler->column_max, &incoming_node->head, data_count, args);
    va_end(args);

    // 添加失败的情况需要释放掉incoming_node及其内部数据
    if(ret != COMMON_TABS_OK) {
        internal_link_list_free(incoming_node->head.next);
        free(incoming_node);
        return ret;
    }

    handler->rear->next = incoming_node;
    handler->rear = incoming_node;

    return ret;
}


/*
Unicode制表符：
┌┬┐    ┌─┐
├┼┤    │┼│
└┴┘    └─┘
*/
int common_tabs_print_unicode_tabs(tab_handler *handler) {
    // step1 打印第一行
    // step2 打印表头
    // step3 打印第三行
    // step4 循环打印数据
    // step5 打印最后一行

    if(handler == NULL) {
        return COMMON_TABS_NEED_INIT;
    }

    if((*handler).handler_header.next == NULL) {
        return COMMON_TABS_HEADERS_ARE_REQUIRED;
    }

    // 设置本地化，以支持宽字符
    setlocale(LC_ALL, "");

    // step1
    internal_print_special_line_unicode(handler, LINE_TYPE1);

    // step2
    internal_print_table_header(handler, PRINTF_FORMAT_UNICODE);

    // step3
    internal_print_special_line_unicode(handler, LINE_TYPE2);

    // step4
    internal_print_table_data(handler, PRINTF_FORMAT_UNICODE);

    // step5
    internal_print_special_line_unicode(handler, LINE_TYPE3);

    return COMMON_TABS_OK;
}

/*
ASCII制表：
+--+
|  |
+--+
*/
int common_tabs_print_ascii_tabs(tab_handler *handler) {
    // step1 打印第一行
    // step2 打印表头
    // step3 打印第三行
    // step4 循环打印数据
    // step5 打印最后一行

    if(handler == NULL) {
        return COMMON_TABS_NEED_INIT;
    }

    if((*handler).handler_header.next == NULL) {
        return COMMON_TABS_HEADERS_ARE_REQUIRED;
    }

    // step1
    internal_print_special_line_ascii(handler);

    // step2
    internal_print_table_header(handler, PRINTF_FORMAT_ASCII);

    // step3
    internal_print_special_line_ascii(handler);

    // step4
    internal_print_table_data(handler, PRINTF_FORMAT_ASCII);

    // step5
    internal_print_special_line_ascii(handler);

    return COMMON_TABS_OK;
}